//
//  QrCodeContentGetter.swift
//  NJU QR
//
//  Created by 许煜恒 on 8/11.
//

import Foundation
import Just
import SwiftUI


func getQrContent(login_cookie:String) throws -> QrContentExtractor {
    let decoder=JSONDecoder()
    let ua = "Mozilla/5.0 (iPhone; CPU iPhone OS 15_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 (5511528960)cpdaily/9.0.14  wisedu/9.0.14"
    //Clear cookie
    let session_config=URLSessionConfiguration.default
    for i in (session_config.httpCookieStorage?.cookies) ?? []{
        session_config.httpCookieStorage?.deleteCookie(i)
    }
    
    let session_response_1=Just.get(
        "https://authserver.nju.edu.cn/authserver/login?service=https%3A%2F%2Fqrcode.nju.edu.cn%3A443%2Fapi%2Fh5",
        headers: ["cookie":login_cookie,"user-agent":ua],
        allowRedirects: false
    )
    let session_redirect_1=session_response_1.headers["Location"]
    guard session_redirect_1 != nil else{
        throw getQrError.failed
    }
    
    let session_response_2=Just.get(
        session_redirect_1!,
        headers: ["user-agent":ua],
        allowRedirects: false
    )
    let session_redirect_2=session_response_2.headers["Location"]
    guard session_redirect_2 != nil else{
        throw getQrError.failed
    }
    let session_2_cookies=convertCookie(session_response_2.cookies)
    guard session_2_cookies.count>0 else{
        throw getQrError.failed
    }
    
    
    let session_response_3=Just.get(
        session_redirect_2!,
        headers: ["user-agent":ua],
        cookies: session_2_cookies,
        allowRedirects: false
    )
    let session_cookie=convertCookie(session_response_3.cookies)
    guard session_cookie.count>0 else{
        throw getQrError.failed
    }
    
    let ticket_response=Just.post(
        "https://qrcode.nju.edu.cn/api/check",
        cookies: session_cookie,
        requestBody: Data()
    )
    let ticket=ticket_response.text
    guard ticket != nil else{
        throw getQrError.failed
    }
    
    let bearer_token_response=Just.post(
        "https://qrcode.nju.edu.cn/code/v1/qrexchange",
        headers: ["ticket":ticket!],
        requestBody: Data()
    )
    let bearer_token_json=bearer_token_response.text
    guard bearer_token_json != nil else{
        throw getQrError.failed
    }
    let bearer_token=try decoder.decode(JwtExtractor.self, from: (bearer_token_json?.data(using: .utf8))!).jwt
    
    let qr_content_response=Just.post(
        "https://qrcode.nju.edu.cn/code/v1/qrcode",
        headers: ["authorization":bearer_token],
        requestBody: Data()
    )
    let qr_content_json=qr_content_response.text
    guard qr_content_json != nil else{
        throw getQrError.failed
    }
    let qr_content=try decoder.decode(QrContentExtractor.self, from: (qr_content_json?.data(using: .utf8))!)
    
    return qr_content
}


func getQrContentAsync(login_cookie:String) -> GetQrResult{
    @ObservedObject var to_return=GetQrResult()
    
    if login_cookie=="" {
        to_return.status = .unconfigured
    } else {
        DispatchQueue.global().async{
            while true{
                do{
                    let result_content = try getQrContent(login_cookie: login_cookie)
                    DispatchQueue.main.async {
                        to_return.result = result_content
                        to_return.status = .successful
                    }
                    sleep(5)
                }catch{
                    DispatchQueue.main.async {
                        to_return.status = .failed
                    }
                    sleep(1)
                }
                
            }
        }
    }
    
    return to_return
    
}


func convertCookie(_ cookies:[String:HTTPCookie]) -> [String:String] {
    var result:[String:String]=[:]
    
    for (key,val) in cookies {
        result[key] = val.value
    }
    
    return result
}

struct JwtExtractor:Codable,Hashable{
    var jwt:String
}

struct QrContentExtractor:Codable,Hashable{
    var qrcode:String
    var qrcodeColor:String
    var color:CGColor {
        switch(qrcodeColor){
        case "绿码":
            return .init(red: 0, green: 1, blue: 0, alpha: 1)
        case "蓝码":
            return .init(red: 0, green: 0, blue: 1, alpha: 1)
        case "灰码":
            return .init(red: 0.5, green: 0.5, blue: 0.5, alpha: 1)
        case "紫码":
            return .init(red: 0.67, green: 0, blue: 1, alpha: 1)
        default:
            print("Unknown Color")
            return .init(red: 0.5, green: 0.5, blue: 0.5, alpha: 1)//Fall back to gray
        }
    }
}

enum getQrStatus{
    case fetching
    case successful
    case failed
    case unconfigured
}
class GetQrResult:ObservableObject{
    @Published var status:getQrStatus = .fetching
    @Published var result:QrContentExtractor?
}

enum getQrError:Error{
    case failed
}
